package cn.tedu._07springaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * Aspect注解：标识此类为切面类;
 */
@Aspect
@Component
public class LogAspect {

    /**
     * Before注解：
     *   1.标识此方法是一个前置通知;
     *   2.调用目标方法之前执行的方法;
     */
    @Before(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void before(JoinPoint joinPoint){
        /*
            1.JoinPoint参数：连接点参数,即拦截到的目标方法对象;
            2.获取方法名和参数列表:
              2.1 获取目标方法名: joinPoint.getSignature().getName();
              2.2 获取目标方法参数列表: joinPoint.getArgs();
         */
        String name = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());

        System.out.println("1.[前置通知]" + name + "方法开始执行,参数为:" + args);
    }

    /**
     * AfterReturning返回通知:
     *   1.目标方法成功执行结束后执行的方法;
     *   2.能够获取到目标方法的返回值;
     */
    @AfterReturning(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result){
        //获取方法名
        String name = joinPoint.getSignature().getName();

        System.out.println("2.[返回通知]" + name + "方法结束,结果为:" + result);
    }

    /**
     * After后置通知：
     *   1.目标方法最终结束后执行的方法;
     *   2.无论目标方法是否抛出异常都会执行;
     *   3.不能够获取目标方法的返回值;
     */
    @After(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void after(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        System.out.println("3.[后置通知]:" + name + "方法最终结束");
    }

    /**
     * AfterThrowing异常通知:
     *   1.目标方法抛出异常时执行的方法;
     *   2.通过throwing参数: 能够获取到目标方法抛出的异常;
     */
    @AfterThrowing(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex){
        String name = joinPoint.getSignature().getName();
        System.out.println("4.[异常通知]:" + name + "方法抛出异常,异常信息为:" + ex.getMessage());
    }

    /**
     * Around环绕通知:
     *   1.环绕在目标方法的每个阶段都可以增强;
     *   2.等价于: 前置通知+返回通知+后置通知+异常通知;
     *   3.通常使用 try ... catch ... finally ... 来实现;
     */
    @Around(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public Object around(ProceedingJoinPoint joinPoint){
        Object result = null;
        //1.前置通知
        System.out.println("环绕通知:前置通知");
        try {
            //执行目标方法
            result = joinPoint.proceed();
            System.out.println("环绕通知:返回通知");
        } catch (Throwable e) {
            System.out.println("环绕通知:异常通知");
            throw new RuntimeException(e);
        } finally {
            System.out.println("环绕通知:后置通知");
        }

        return result;
    }
}

















